#include "glwin.h"
#include "gltool.h"
#include "glmath.h"
#include "glnavig.h"

typedef enum _FUNC_TYPE {
	FUNC_NONE=0,
	FUNC_EXP,
	FUNC_LOG,
	FUNC_SIN,
	FUNC_COS,
	FUNC_TAN,
	FUNC_ASIN,
	FUNC_ACOS,
	FUNC_ATAN
	} FUNC_TYPE;

typedef double (*dfdx)(double,int);
double df(double e,int k)
{
	if(!k)
		return 1;
	if(k%2)
		return 0;
	return sign1(k/2)*(1<<(k-1))*e*e;
}
double e=E_EARTH,ae=A_EARTH;

class Expression
{ // Expression A
	friend class Calculator;
protected:
	Expression *prev,*next,*connect;
	BYTE d; // number of diffs for the user function
public:
	Expression *add,*mul,*child; // child*mul+add
	float factor; // factor*(A)
	float coef; // coef*A
	float cnst; // If type Is 0 Then A=const, Otherwise (A)+cnst
	float pow; // A^pow
	_TCHAR func; // func(A), If func<0 Then User Function Specified By ID=(1-func)
	_TCHAR type; // type<0 => A'=child; type=0 => A'=cnst; type>0 => A'=var[type-1];
	 // A=factor*((coef*(func(A'))^pow)*mul+add+cnst)
#ifdef DEBUG_MATH
	unsigned long id;
#endif
	Expression()
	{
		add=NULL;
		mul=NULL;
		child=NULL;
		prev=NULL;
		next=NULL;
		connect=NULL;
		factor=1;
		coef=1;
		cnst=0;
		func=0;
		pow=1;
		type=0;
		d=0;
	}

};

class Calculator
{
protected:
	Expression *input, *last, *first;
	UINT count;
	int varID;
	dfdx *userf;
	double *var;
	STR *userfNames;
	STR *varNames;
	DynamicString dstr;
	String str;
	//BOOL trimVar(Expression *expr);
	void addStr(DynamicString& str, int depth, const Expression *expr);
	double getValue(const Expression *expr);
	Expression * getDiff(const Expression *expr);
	void connectTree(Expression *expr); // Connect The Tree Of expr
	double evalFunc(const Expression *expr, double x);
	void addFuncName(DynamicString& str, const Expression *expr);
	// Create A True Func Expression, MUL = 0, ADD = 0, CNST = 0
	Expression * diffFunc(const Expression *expr);
	BOOL needParent(const Expression *expr) const
	{
		if(expr->type)	// fact(coef.func(A)^pow)mul+add+cnst => fact(coef.func(A)^pow)
			return expr->mul||expr->add||expr->cnst;
		else			// fact(coef.func(cnst)^pow)mul+add => fact(coef.func(cnst)^pow)
			return expr->mul||expr->add;
	}
	BOOL isPureParent(const Expression *expr) const
	{
		return // fact(coef.func(A)^pow)mul+add+cnst => A
			expr
			&&expr->type<0
			&&expr->child
			&&!expr->add
			&&!expr->mul
			&&!expr->cnst
			&&!expr->func
			&&expr->factor==1
			&&expr->coef==1
			&&expr->pow==1;
	}
	BOOL isPureConst(const Expression *expr) const
	{
		return // fact(coef.func(cnst)^pow)mul+add => fact(coef.func(cnst)^pow)
			expr
			&&!expr->type
			&&!expr->mul
			&&!expr->add;
	}
	// Removes Extra Parents From A Child Expression
	Expression * getTrueChild(Expression *expr) const
	{
		if(isPureParent(expr))
			return getTrueChild(expr->child);
		return expr;
	}
public:
	NumberFormat format;
	int strDepth;
	dfdx *defUserf; // Default User Functions
	double *defVar; // Default Variables
	STR *defUserfNames; // Default User Function Names
	STR *defVarNames; // Default Variable Names
	BOOL newLine;
	Calculator();
	~Calculator();
	void del(Expression * expr);
	// Create An Empty Expression (0)
	Expression * create();
	// expr = (type!=0) factor.A + cnst, (type=0) factor.A
	// A = B.mul + add
	// B = coef.func(C)^pow
	// C = (type<0) child, (type>0) var, (type=0) cnst
	Expression * create(
						int type,
						int func = 0,
						double coef = 1,
						double pow = 1,
						double cnst = 0,
						double factor = 1,
						Expression *add = NULL,
						Expression *mul = NULL,
						Expression *child = NULL);
	// Create And Copy
	Expression * create(const Expression * model);
	// Shortcut To Create Constant Cnst
	Expression * createc(float cnst);
	// Shortcut To Create Parent Expression (0)
	Expression * createp(Expression *child, double pow = 1, BOOL ifNeeded = FALSE, BOOL trueChild = TRUE);
	// Shortcut To Create Variable 0
	Expression * createv(int varID, double coef = 1, double pow = 1);
	// Shortcut To Create A Function f(0)
	Expression * createf(int funcID, int type, Expression *child = NULL, int diffs = 0);
	void clear(); // Delete All Created Expressions
	int clearUnused(Expression *expr); // Delete All Expressions Not In The Tree Of expr
	void remExtraParent(Expression *expr); // Delete All Extra Parent Expressions In The Tree Of expr
	Expression * diff(Expression *expr, int varID = 1);
	Expression * diffn(Expression *expr, int nDiff = 1, int varID = 1)
	{
		for(int i=0;i<nDiff;i++)
		{
			expr=diff(expr,varID);
			clearUnused(expr);
		}
		return expr;
	}
	double eval(Expression *expr, double *var = NULL,  dfdx *userf = NULL);
	//void resolve(int varID, Expression *expr, double *var = NULL,  dfdx *userf = NULL);
	STR  toString(const Expression *expr, STR *varNames = NULL,  STR *userfNames = NULL, int depth = 0);
	UINT getExprCount() const
	{
		return count;
	}
};